/*
 * Copyright (C) 2010 Seapeak.Xu
 *
 * fostmq may be copied only under the terms of the GNU General
 * Public License V3, which may be found in the fostmq source kit.
 *
 * Created on: 2010-7-28
 * Author: Seapeak.Xu
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

#include "fost_mgnb.h"
#include "fost_io.h"
#include "fost_mem.h"
#include "fost_typedef.h"
#include "fost_datetime.h"

static int _fd = STDERR_FILENO;
static size_t _linesize = 20000;
static size_t _level = 7;
static size_t _lines = 0;
static char _suffix[PATH_LEN];
static pthread_mutex_t _locker = PTHREAD_MUTEX_INITIALIZER;

static int open_logfile(const char *path);
static void do_log(const char *message);

#define _DO_LOG(msg_prefix,level) \
	if(level > _level)\
return;\
int result = 0;\
char *text = fost_callocs(LINE_LEN);\
if(NULL == text)\
{\
	result = 0 == errno ? ENOMEM : errno;\
	return;\
}\
char datetime[DATETIME_LEN_SEPY] ;\
format_datetime_by_separator(NULL,DATETIME_LEN_SEPY,datetime);\
int msg_prefix_length = strlen(msg_prefix);\
result = snprintf(text,LINE_LEN,"%s:%s",datetime,msg_prefix);\
if(-1 == result || DATETIME_LEN_SEPY + msg_prefix_length != result )\
{\
	result = 0 == errno ? ENOMEM : errno;\
	printf("Error!File:%s,Line:%d.Errno:%d,Info:%s.",__FILE__,__LINE__,result,strerror(result));\
	return;\
}\
va_list arg_ptr;\
va_start(arg_ptr,format);\
do\
{\
	result = vsnprintf(text+DATETIME_LEN_SEPY+msg_prefix_length,LINE_LEN-DATETIME_LEN_SEPY-msg_prefix_length ,format,arg_ptr);\
	va_end(arg_ptr);\
	if(-1 == result || LINE_LEN < result)\
	{\
		result = 0 == errno ? ENOMEM : errno;\
		printf("Error!File:%s,Line:%d.Errno:%d,Info:%s.",__FILE__,__LINE__,result,strerror(result));\
		break;\
	}\
	text[result + DATETIME_LEN_SEPY + msg_prefix_length] = '\n';\
	do_log(text);\
} while(0);\
FOST_FREE(text);\


static int open_logfile(const char *path)
{
	int result = 0;
	char *log_filename;

	log_filename = fost_callocs(PATH_LEN);
	if (NULL == log_filename)
	{
		result = 0 == errno ? ENOMEM : errno;
		printf("Error!File:%s,Line:%d.malloc memory is error.Errno:%d,Info:%s.", __FILE__, __LINE__,
				result,strerror(result));
		return result;
	}

	char datetime[DATETIME_LEN_NOSEPY];
	format_datetime(NULL, DATETIME_LEN_NOSEPY, datetime);
	do
	{
		result = snprintf(log_filename, PATH_LEN, "%s%s", path, datetime);
		if (-1 == result || PATH_LEN <= result)
		{
			result = 0 == errno ? ENOMEM : errno;
			printf("Error!File:%s,Line:%d.Errno:%d,Info:%s.", __FILE__,
					__LINE__, result,strerror(result));
			break;
		}
		if (0 > (_fd = open(log_filename, O_RDWR | O_CREAT | O_APPEND
						| O_SYNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
						|S_IWOTH)))
		{
			result = errno;
			_fd = STDERR_FILENO;
			printf("Error!File:%s,Line:%d.Errno:%d,Info:%s.", __FILE__,
					__LINE__,result, strerror(result));
			break;
		}
		result = 0;
	} while (false);

	FOST_FREE(log_filename);
	return result;
}

int logger_init(const char *path, const char *prefix, const size_t linesize,
		const size_t level)
{
	int result = 0;
	_linesize = linesize;
	_level = level;

	if (0 != (result = mkdir_cascading(path, 777)))
	{
		printf("Error!File:%s,Line:%d.Errno:%d,Info:%s.", __FILE__, __LINE__,
				result,strerror(result));
		return result;
	}

	result = snprintf(_suffix, PATH_LEN - 1, "%s/%s_log", path,prefix);
	if (result >= PATH_LEN)
	{
		printf("Error!File:%s,Line:%d.Error info is log_file path length:%d is greater then MAX_PATH:%d! ",
				__FILE__, __LINE__, result, PATH_LEN);
		return result;
	}

	result = open_logfile(_suffix);
	return result;
}

void logger_close()
{
	fsync(_fd);
	close(_fd);
	_fd = STDERR_FILENO;
}

static void do_log(const char *message)
{
	int result = 0;
	pthread_mutex_lock(&_locker);
	do
	{
		if (_linesize <= _lines)
		{
			logger_close();
			if (0 != (result = open_logfile(_suffix)))
			{
				_fd = STDERR_FILENO;
				//	result = 0 == errno ? EIO : errno;
				printf("Error!File:%s,Line:%d.Errno:%d,Info:%s.", __FILE__,
						__LINE__, result,strerror(result));
				break;
			}
			_lines = 0;
		}
		int length = strlen(message);
		do
		{
			result += write(_fd, message + result, length - result);
		} while (length != result);

		_lines++;
	} while (false);
	pthread_mutex_unlock(&_locker);
	return;
}

void log_emery(const char *format, ...)
{
	_DO_LOG("Emery!",0);
}
void log_alert(const char *format, ...)
{
	_DO_LOG("Alert!",1);
}
void log_crit(const char *format, ...)
{
	_DO_LOG("Crit!",2);
}
void log_error(const char *format, ...)
{
	_DO_LOG("Error!",3);
}
void log_warn(const char *format, ...)
{
	_DO_LOG("Warn!",4);
}
void log_notice(const char *format, ...)
{
	_DO_LOG("Notice!",5);
}
void log_info(const char *format, ...)
{
	_DO_LOG("Info!",6);
}
void log_debug(const char *format, ...)
{
	_DO_LOG("Debug!",7);
	/* 
	   int level = 7;
	   char *msg_prefix = "Debug!";
	   if(level > level)
	   return;
	   int result = 0;
	   char *text = (char *) fost_calloc(MAX_LINE,sizeof(char));
	   if(NULL == text)
	   {
	   errno = 0 == errno ? ENOMEM : errno;
	   return;
	   }
	   char datetime[DATETIMELENWITHSEPY] ;
	   format_datetime_by_separator(NULL,DATETIMELENWITHSEPY,datetime);
	   int msg_prefix_length = strlen(msg_prefix);
	   result = snprintf(text,MAX_LINE,"%s:%s",datetime,msg_prefix);
	   if(-1 == result || DATETIMELENWITHSEPY + msg_prefix_length != result )
	   {
	   errno = 0 == errno ? ENOMEM : errno;
	   printf("Error!File:%s,Line:%d.Errno:%d,Info:%s.",__FILE__,__LINE__,errno,strerror(errno));
	   result = -1;
	   return;
	   }
	   va_list arg_ptr;
	   va_start(arg_ptr,format);
	   do
	   {
	   result = vsnprintf(text+DATETIMELENWITHSEPY+msg_prefix_length,MAX_LINE-DATETIMELENWITHSEPY-msg_prefix_length ,format,arg_ptr);
	   va_end(arg_ptr);
	   if(-1 == result || MAX_LINE < result)
	   {
	   errno = 0 == errno ? ENOMEM : errno;
	   printf("Error!File:%s,Line:%d.Errno:%d,Info:%s.",__FILE__,__LINE__,errno,strerror(errno));
	   result = -1;
	   break;
	   }
	   text[result + DATETIMELENWITHSEPY + msg_prefix_length] = '\n';
	   do_log(text);
	   } while(0);
	   FOST_FREE(text);
	   */	
}
